package ms.unicorn.dsl.impl;

import ms.unicorn.EPhantomAttribute;
import ms.unicorn.Element;
import ms.unicorn.Entity;
import ms.unicorn.UnicornPackage;
import ms.unicorn.dsl.IElementField;
import ms.unicorn.dsl.runtime.ExecutionContext;
import ms.unicorn.dsl.runtime.interpreter.XFunctionDeclartationInterpreter;
import ms.unicorn.dsl.unicornDSL.ElementField;
import ms.unicorn.dsl.unicornDSL.XExpression;
import ms.unicorn.dsl.unicornDSL.XFunctionDeclaration;
import ms.unicorn.dsl.unicornDSL.XReturnStatement;
import ms.unicorn.dsl.utils.ExceptionUtil;

import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EDataType;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.impl.EAttributeImpl;
import org.eclipse.emf.ecore.impl.ENotificationImpl;

public class EPhantomAttributeImpl extends EAttributeImpl implements EPhantomAttribute {

	private IElementField fieldDef;
	private boolean visible;
	private String category;
	private String displayName;
	private String description;
	private boolean multiline;
	private boolean sortchoice;
	private Object image;
	
	public EPhantomAttributeImpl(IElementField def, Class<?> containerClass, EClass containerEClass) {
		fieldDef = def;
		
		setName(fieldDef.getName());
		setEType(fieldDef.getDataType());
		setTransient(true);		
		setChangeable(fieldDef.isEditable());
		setVisible(fieldDef.isVisible());
		setCategory(fieldDef.getCategory());
		
		displayName = fieldDef.getDisplayName();
		description = fieldDef.getDescription();
		multiline = fieldDef.isMultiLine();
		sortchoice = false; //ParameterUtil.getParameter(params, "sortchoice", false);
		
		
		setContainerClass(containerClass);
		//EClass eClass = UnicornPackage.eINSTANCE.getEntity();
		containerEClass.getEStructuralFeatures().add(this);
		setFeatureID(containerEClass.getEStructuralFeatures().size());
	}

	public IElementField getFieldDef() {
		return fieldDef;
	}

	public void setFieldDef(IElementField fieldDef) {
		this.fieldDef = fieldDef;
	}

	public <T> T getValue(Element e) {
		if (fieldDef.getDefaultValue() instanceof XExpression) {
			XExpression exp = (XExpression) fieldDef.getDefaultValue();
			ExecutionContext context = ModelLanguage.context.createChildContext();
			context.setThisObject(e);		
			Object value = null;
			try {
			if (exp instanceof XFunctionDeclaration) 
				value = XFunctionDeclartationInterpreter.interpret(ModelLanguage.interpreter, (XFunctionDeclaration)exp, context);
			else
				value  = ModelLanguage.interpreter.resolveValue(exp, context);
			}
			catch(Exception e1) {
				ExceptionUtil.handleException(e1);
				return null;
			}
			return (T)value;
		}
		if (fieldDef.getDataType() instanceof EDataType)
			return e.getProperty((EDataType) fieldDef.getDataType(), fieldDef.getName());
		else if (fieldDef.getDataType() instanceof EClass) {
			String url = e.getProperty(LanguageElementField.STRING, fieldDef.getName());
			return (T) e.eResource().getResourceSet().getEObject(URI.createURI(url), true);
		}
		else {
			return e.getProperty(LanguageElementField.STRING, fieldDef.getName());
		}
	}
	
	public <T> void setValue(Element e, T value) {
		Object oldValue = getValue(e);
		if (fieldDef.getDataType() instanceof EDataType)
			e.setProperty((EDataType) fieldDef.getDataType(), fieldDef.getName(), value);
		else if (fieldDef.getDataType() instanceof EClass) {
			Element obj = (Element) value;
			e.setProperty(LanguageElementField.STRING, fieldDef.getName(), String.format("%s#%s", obj.eResource().getURI(), obj.getId()));
		}
		else 
			e.setProperty(LanguageElementField.STRING, fieldDef.getName(), value);
		e.eNotify(new ENotificationImpl((InternalEObject) e, Notification.SET, this, oldValue, getValue(e)));
	}

	public boolean isVisible() {
		return visible;
	}

	public void setVisible(boolean visible) {
		this.visible = visible;
	}

	public String getCategory() {
		return category;
	}

	public void setCategory(String group) {
		this.category = group;
	}

	@Override
	public String getDisplayName() {
		return this.displayName != null ? this.displayName : getName();
	}

	@Override
	public String getDescription() {
		return this.description;
	}

	@Override
	public boolean isMultiLine() {
		return this.multiline;
	}

	@Override
	public boolean isSortChoice() {
		return this.sortchoice;
	}

	@Override
	public Object getImage() {
		return this.image != null ? this.image : fieldDef.getDefaultImage();
	}

}
